export class BinaryWriter {
    private _buffer: ArrayBuffer = null!;
    private _view: DataView = null!;
    private _offset: number = 0;
    public get offset(): number {
        return this._offset;
    }
    public set offset(value: number) {
        this._offset = value;
    }
    

    constructor() {
        this._buffer = new ArrayBuffer(1024);
        this._view = new DataView(this._buffer);
        this._offset = 0;
    }


    public length(): number {
        return this._buffer.byteLength;
    }


    public dispose(): void {

    }

    public writeByte(value: number) {
        this.ensureCapacity(1);
        this._view.setUint8(this._offset, value);
        this._offset += 1;
    }

    public writeBoolean(b: boolean): void {
        this.ensureCapacity(1);
        this._view.setUint8(this._offset, b ? 1 : 0);
        this._offset += 1;
    }

    public writeInt32(i: number): void {
        this.ensureCapacity(4);
        this._view.setInt32(this._offset, i, true);
        this._offset += 4;
    }

    public writeFloat32(f: number): void {
        this.ensureCapacity(4);
        this._view.setFloat32(this._offset, f, true);
        this._offset += 4;
    }

    public writeString(value: string): void {
        const encoder = new TextEncoder();
        const encodedString = encoder.encode(value);
        this.ensureCapacity(encodedString.length);
        new Uint8Array(this._buffer, this._offset, encodedString.length).set(encodedString);
        this._offset += encodedString.length;
    }


    public writeFloatList(floatList: number[]): void {
        this.writeInt32(floatList.length);
        for (const f of floatList) {
            this.writeFloat32(f);
        }
    }

    public writeByteArray(data: Uint8Array): void {
        this.ensureCapacity(data.length);
        for (const b of data) {
            this._view.setUint8(this._offset, b);
            this._offset += 1;
        }
    }

    public setRawBytes(data: Uint8Array): void {
        this._offset = 0;
        this._buffer = new ArrayBuffer(data.length);
        for (const b of data) {
            this._view.setUint8(this._offset, b);
            this._offset += 1;
        }
    }

    /**
     * @en Read the byte array of the message.
     * @zh 读取消息的字节数组。
     */
    public toByteArray(): Uint8Array {
        return new Uint8Array(this._buffer, 0, this._offset);
    }

    private ensureCapacity(size: number) {
        if (this._offset + size > this._buffer.byteLength) {
            const newBuffer = new ArrayBuffer(this._buffer.byteLength * 2);
            new Uint8Array(newBuffer).set(new Uint8Array(this._buffer));
            this._buffer = newBuffer;
            this._view = new DataView(this._buffer);
        }
    }
}